/*************************************************************************************
 * Nombre del archivo: FCB.java
 * Universidad del Valle de Guatemala
 * Curso: Sistemas Operativos
 * @author martin
 *          Martín Guzmán 08041
 * Fecha: Mayo de 2010
 * Descripción: File Control Block
*************************************************************************************/
import java.io.File;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FCB {

    /*
     id	-> número de FCB (0-83)		2
    nombre	-> espacio indica final del nombre.. letras|numeros|\\.	32
    tamaño real	->	tamaño en bytes del archivo	7
    #primer_bloque_datos	-> número del primer bloque de datos	4
    fecha_creacion	-> almacenado como UTC	32
    fecha_modificacion	-> almacenado como UTC	32
    carpeta o archivo	-> a = archivo, c=carpeta	1
    id_padre	-> carpeta a la que pertenece	2
    id_hermano	-> id del siguiente archivo que pertenece a la misma carpeta 	2
    Espacio_sin_utilizar	-> después 142
     */
    final int tamano_espacio_vacio = 142;
    final int tamano_id = 2;
    final int tamano_nombre = 32;
    final int tamano_tamano_real = 7;
    final int tamano_numero_primer_bloque_datos = 4;
    final int tamano_fecha_UTC = 32;
    final int tamano_carpeta = 1;

    private String id = "";
    private String nombre = "";
    private String tamano_real = "";
    private String primer_bloque_de_datos = "";
    private String fecha_creacion = "";
    private String fecha_modificacion = "";
    private String carpeta_archivo = "";
    private String id_padre = "";
    private String id_hermano = "";
    public String Espacio_sin_utilizar = "";


    /***********************************************
     * Método: FCB
     * Uso: constructor
    ***********************************************/
    public FCB(){
        Init(-1," ","0","","a",-1,-1);
    }

    /***********************************************
     * Método: FCB
     * Uso: constructor
    ***********************************************/
    public FCB(int id){
        if(id<FileSystem.Cantidad_FCB && id>=0){
            this.Init(id," ","0","","a",-1,-1);
        }

    }

    /***********************************************
     * Método: FCB
     * Uso: inicializa el FCB con una cadena de entrada
     * @return boolean indicando si era correcta o no
    ***********************************************/
    public boolean FCB(String cadena){
        //la cadena es de un tamaño específico
        int largo = this.tamano_carpeta + this.tamano_espacio_vacio + 2*this.tamano_fecha_UTC + 3*this.tamano_id + this.tamano_nombre + this.tamano_numero_primer_bloque_datos + this.tamano_tamano_real;
        if(cadena.length()!=(largo)){
            System.out.println("FCB.FCB-boolean: largo incorrecto.. tiene que ser de: "+largo+" y es de: "+cadena.length());
            return false;
        }
        String id = "";
        String nombre = "";
        String tamano_real = "";
        String primer_bloque_de_datos = "";
        String fecha_creacion = "";
        String fecha_modificacion = "";
        String carpeta_archivo = "";
        String id_padre = "";
        String id_hermano = "";
        String Espacio_sin_utilizar = "";
        try{
            String cadena2 = cadena;
            id = cadena2.substring(0, this.tamano_id);
            cadena2 = cadena2.substring(this.tamano_id);
            nombre = cadena2.substring(0, this.tamano_nombre);
            cadena2 = cadena2.substring(this.tamano_nombre);
            tamano_real = cadena2.substring(0,this.tamano_tamano_real);
            cadena2 = cadena2.substring(this.tamano_tamano_real);
            primer_bloque_de_datos = cadena2.substring(0,this.tamano_numero_primer_bloque_datos);
            cadena2 = cadena2.substring(this.tamano_numero_primer_bloque_datos);
            fecha_creacion = cadena2.substring(0,this.tamano_fecha_UTC);
            cadena2 = cadena2.substring(this.tamano_fecha_UTC);
            fecha_modificacion = cadena2.substring(0,this.tamano_fecha_UTC);
            cadena2 = cadena2.substring(this.tamano_fecha_UTC);
            carpeta_archivo = cadena2.substring(0,this.tamano_carpeta);
            cadena2 = cadena2.substring(this.tamano_carpeta);
            id_padre = cadena2.substring(0, this.tamano_id);
            cadena2 = cadena2.substring(this.tamano_id);
            id_hermano = cadena2.substring(0, this.tamano_id);
        }catch(Exception exp){
            System.out.println("FCB.FCB-boolean: Hubo un error en un substring");
            return false;
        }
        if(!this.setId(id)){
            System.out.println("FCB.FCB-boolean: Problema con el id: ."+id+". tamaño: "+id.length());
            return false;
        }
        if(!this.setCarpeta_archivo(carpeta_archivo)){
            System.out.println("FCB.FCB-boolean: Problema con carpeta_archivo: ."+carpeta_archivo+". tamaño: "+carpeta_archivo.length());
            return false;
        }
        if(!this.setNombre(nombre)){
            System.out.println("FCB.FCB-boolean: Problema con nombre: ."+nombre+". tamaño: "+nombre.length());
            return false;
        }
        if(!this.setFecha_creacion(fecha_creacion)){
            System.out.println("FCB.FCB-boolean: Problema con la fecha de creación: ."+fecha_creacion+". tamaño: "+fecha_creacion.length());
            return false;
        }
        if(!this.setFecha_modificacion(fecha_modificacion)){
            System.out.println("FCB.FCB-boolean: Problema con la fecha_modificacion: ."+fecha_modificacion+". tamaño: "+fecha_modificacion.length());
            return false;
        }
        if(!this.setPrimer_bloque_de_datos(primer_bloque_de_datos)){
            System.out.println("FCB.FCB-boolean: Problema con primer_bloque_de_datos: ."+primer_bloque_de_datos+". tamaño: "+primer_bloque_de_datos.length());
            return false;
        }
        if(!this.setId_hermano(id_hermano)){
            System.out.println("FCB.FCB-boolean: Problema con el id_hermano: ."+id_hermano+". tamaño: "+id_hermano.length());
            return false;
        }
        if(!this.setId_padre(id_padre)){
            System.out.println("FCB.FCB-boolean: Problema con el id_padre: ."+id_padre+". tamaño: "+id_padre.length());
            return false;
        }
        if(!this.setTamano_real(tamano_real)){
            System.out.println("FCB.FCB-boolean: Problema con el tamano_real: ."+tamano_real+". tamaño: "+tamano_real.length());
            return false;
        }
        

        return true;
    }
    
    /***********************************************
     * Método: Init
     * Uso: para inicializar un FCB
    ***********************************************/
    public void Init(int id,String nombre, String tamano_real, String primer_bloque_de_datos, String carpeta_archivo, int id_padre, int id_hermano){
        this.setId(id);
        this.setNombre(nombre);
        this.setTamano_real(tamano_real);
        this.setPrimer_bloque_de_datos(primer_bloque_de_datos);
        this.setFecha_creacion();
        this.setFecha_modificacion();
        this.setCarpeta_archivo(carpeta_archivo);
        this.setId_padre(id_padre);
        this.setId_hermano(id_hermano);
        this.setEspacioSinUtilizar();
    }

    /***********************************************
     * Método: toString
     * Uso: Devuelve una cadena con el string que representa el FCB
    ***********************************************/
    public String toString(){
        String retorno = "";

        retorno+= this.id;
        retorno+= this.nombre;
        retorno+= this.tamano_real;
        retorno+= this.primer_bloque_de_datos;
        retorno+= this.fecha_creacion;
        retorno+= this.fecha_modificacion;
        retorno+= this.carpeta_archivo;
        retorno+= this.id_padre;
        retorno+= this.id_hermano;
        retorno+= this.Espacio_sin_utilizar;

        return retorno;
    }

    /***********************************************
     * Método: isEmpty
     * Uso: Devuelve el id de este FCB
     * @return the id
    ***********************************************/
    public boolean isEmpty() {
        /*
        if(this.isCarpeta()){
            return false;
        }
        int valor = this.getPrimer_bloque_de_datos_value();
        if(valor==-1){
            return true;
        }
         */
        int valor = this.getId_value();
        if(valor==-1){
            return true;
        }
        return false;
    }

    /***********************************************
     * Método: reset
     * Uso: borra todo menos el id
     * @return the id
    ***********************************************/
    public boolean reset() {
        this.Init(-1," ","0","","a",-1,-1);
        return true;
    }

    /***********************************************
     * Método: createFolder
     * Uso: crea un archivo como carpeta
     * @return booleano si se creó correctamente
    ***********************************************/
    public boolean createFolder(String nombre) {
        this.reset();
        if(this.setNombre(nombre)==false){
            return false;
        }
        this.setCarpeta_archivo("c");
        return true;
    }

    /***********************************************
     * Método: getId
     * Uso: Devuelve el id de este FCB
     * @return the id
    ***********************************************/
    public String getId() {
        return id.trim();
    }

    /***********************************************
     * Método: getId_value
     * Uso: Devuelve el id de este FCB cono un valor numérico
     * @return the id
    ***********************************************/
    public int getId_value(){
        int a = 0;
        try{
            a = Integer.parseInt(this.id.trim());
        }catch(Exception exp){
            return -1;
        }
        return a;
    }

    /***********************************************
     * Método: setId
     * Uso: setea el contenido de id
     * @param id the id to set
    ***********************************************/
    public boolean setId(String id) {
        //para que sean 2
        String a = id;
        //si es más grande no puede ser id
        if(a.length()>this.tamano_id){
            return false;
        }
        try{
            Integer.parseInt(a.trim());
        }catch(Exception exp){
            if(!a.trim().isEmpty()){
                return false;
            }
        }
        for(int i=a.length();i<this.tamano_id;i++){
            a+=" ";
        }
        this.id = a;
        return true;
    }

    /***********************************************
     * Método: setId
     * Uso: setea el contenido de id
     * @param id the id to set
    ***********************************************/
    public void setId(int id) {
        int tam_a_completar = 0;
        if(id>99 || id<-1){
            tam_a_completar=this.tamano_id-0;
        }
        else if(id>9 || id==-1){
            tam_a_completar=this.tamano_id-2;
        }
        else{
            tam_a_completar=this.tamano_id-1;
        }
        String a = ""+id;
        for(int i=0;i<tam_a_completar;i++){
            a+=" ";
        }
        this.id = a;
    }

    /***********************************************
     * Método: getNombre
     * Uso: Devuelve el nombre de este FCB
     * @return el nombre hasta el primer espacio
    ***********************************************/
    public String getNombre() {
        return this.nombre.trim();
    }

    /***********************************************
     * Método: setNombre
     * Uso: setea el contenido de nombre
     * @param nombre contiene lo que se va a meter
     *      que no puede ser mayor a 32 o se corta
    ***********************************************/
    public boolean setNombre(String nombre) {
        //para que sean 32
        String a = nombre;
        //si es más grande corta la cadena...
        if(a.length()>this.tamano_nombre){
            return false;
        }
        for(int i=a.length();i<this.tamano_nombre;i++){
            a+=" ";
        }
        this.nombre = a;
        return true;
    }

    /***********************************************
     * Método: getTamano_real
     * Uso: Devuelve el nombre de este FCB
     * @return el tamano real hasta el primer espacio
    ***********************************************/
    public String getTamano_real() {
        return this.tamano_real.trim();
    }

    /***********************************************
     * Método: getTamano_real_value
     * Uso: Devuelve el nombre de este FCB, como valor
     * @return el tamano real hasta el primer espacio
    ***********************************************/
    public int getTamano_real_value() {
        String a = this.tamano_real.split(" ")[0];
        try{
            return Integer.parseInt(a);
        }catch(Exception exp){
            return -1;
        }
    }

    /***********************************************
     * Método: setTamano_real
     * Uso: setea el contenido de nombre
     * @param nombre contiene lo que se va a meter
     *      que no puede ser mayor a 32 o se corta
    ***********************************************/
    public boolean setTamano_real(String tamano_real) {
        //para que sean 7
        String a = tamano_real;
        //si es más grande corta la cadena...
        if(a.length()>this.tamano_tamano_real){
            return false;
        }
        try{
            Integer.parseInt(a.trim());
        }catch(Exception exp){
            if(!a.trim().isEmpty()){
                return false;
            }
        }
        for(int i=a.length();i<this.tamano_tamano_real;i++){
            a+=" ";
        }
        this.tamano_real = a;
        return true;
    }

    /***********************************************
     * Método: getPrimer_bloque_de_datos
     * Uso: Devuelve el índice del primer bloque de datos de este FCB
     * @return índice del primer bloque
    ***********************************************/
    public String getPrimer_bloque_de_datos() {
        return primer_bloque_de_datos.trim();
    }

    /***********************************************
     * Método: getPrimer_bloque_de_datos
     * Uso: Devuelve el índice del primer bloque de datos de este FCB
     * @return índice del primer bloque
    ***********************************************/
    public int getPrimer_bloque_de_datos_value() {
        try{
            return Integer.parseInt(primer_bloque_de_datos.trim());
        }catch(Exception exp){
            return -1;
        }
    }

    /***********************************************
     * Método: setPrimer_bloque_de_datos
     * Uso: setea el contenido de primer_bloque_de_datos
     * @param contiene lo que se va a meter como
     *      primer bloque de datos
    ***********************************************/
    public boolean setPrimer_bloque_de_datos(String primer_bloque_de_datos) {
        //para que sean 4
        String a = primer_bloque_de_datos;
        //si es más grande corta la cadena...
        if(a.length()>this.tamano_numero_primer_bloque_datos){
            FileSystem.PrintDebug("FCB.setPrimer_bloque_de_datos: tamaño incorrecto: "+primer_bloque_de_datos.length());
            return false;
        }
        try{
            Integer.parseInt(a.trim());
        }catch(Exception exp){
            if(!a.trim().isEmpty()){
                return false;
            }
        }
        for(int i=a.length();i<this.tamano_numero_primer_bloque_datos;i++){
            a+=" ";
        }
        this.primer_bloque_de_datos = a;
        return true;
    }

    /***********************************************
     * Método: getFecha_creacion
     * Uso: Devuelve la fecha de creación
     * @return string con la fecha
    ***********************************************/
    public String getFecha_creacion() {
        return fecha_creacion.trim();
    }

    /***********************************************
     * Método: getFecha_creacion_formato
     * Uso: Devuelve en un formato la fecha de creación
     * @return string con la fecha
    ***********************************************/
    public String getFecha_creacion_formato() {
        try{
            long a = Long.parseLong(fecha_creacion.trim());
            Date fecha = new Date(a);
            return fecha.toString();
        }catch(Exception exp){
            return "";
        }
    }

    /***********************************************
     * Método: setFecha_creacion_formato
     * Uso: setea la fecha de creación del archivo
     * @param fecha_creación
    ***********************************************/
    public boolean setFecha_creacion(String fecha_creacion) {
        //para que sean 32
        String a = ""+fecha_creacion;
        //si es más grande no puede ser fecha
        if(a.length()>this.tamano_fecha_UTC){
            FileSystem.PrintDebug("FCB.setFecha_creacion: el tamaño es incorrecto: "+fecha_creacion.length());
            return false;
        }
        try{
            Long.parseLong(a.trim());//si no es long no puede ser una fecha UTC
        }catch(Exception exp){
            return false;
        }
        for(int i=a.length();i<this.tamano_fecha_UTC;i++){
            a+=" ";
        }
        this.fecha_creacion = a;
        return true;
    }

    /***********************************************
     * Método: setFecha_creacion_formato
     * Uso: setea la fecha de creación del archivo con
     *      la fecha actual
    ***********************************************/
    public void setFecha_creacion() {
        Date fecha = new Date();
        //para que sean 32
        String a = ""+fecha.getTime();
        for(int i=a.length();i<this.tamano_fecha_UTC;i++){
            a+=" ";
        }
        //si es más grande corta la cadena...
        if(a.length()>this.tamano_fecha_UTC){
            a = a.substring(0, this.tamano_fecha_UTC);
        }
        this.fecha_creacion = a;
    }

    /***********************************************
     * Método: getFecha_modificacion
     * Uso: Devuelve la fecha de modificacion
     * @return string con la fecha
    ***********************************************/
    public String getFecha_modificacion() {
        return fecha_modificacion.trim();
    }

    /***********************************************
     * Método: getFecha_modificacion_formato
     * Uso: Devuelve en un formato la fecha de modificacion
     * @return string con la fecha
    ***********************************************/
    public String getFecha_modificacion_formato() {
        try{
            long a = Long.parseLong(fecha_modificacion.trim());
            Date fecha = new Date(a);
            return fecha.toString();
        }catch(Exception exp){
            return "";
        }
    }

    /***********************************************
     * Método: setFecha_modificacion
     * Uso: setea la fecha de creación del archivo
     * @param fecha_creación
    ***********************************************/
    public boolean setFecha_modificacion(String fecha_modificacion) {
        //para que sean 32
        String a = ""+fecha_modificacion;
        //si es más grande no puede ser fecha
        if(a.length()>this.tamano_fecha_UTC){
            return false;
        }
        try{
            Long.parseLong(a.trim());//si no es long no puede ser una fecha UTC
        }catch(Exception exp){
            return false;
        }
        for(int i=a.length();i<this.tamano_fecha_UTC;i++){
            a+=" ";
        }
        
        this.fecha_modificacion = a;
        return true;
    }

    /***********************************************
     * Método: setFecha_creacion_formato
     * Uso: setea la fecha de creación del archivo con
     *      la fecha actual
    ***********************************************/
    public void setFecha_modificacion() {
        Date fecha = new Date();
        //para que sean 32
        String a = ""+fecha.getTime();
        for(int i=a.length();i<this.tamano_fecha_UTC;i++){
            a+=" ";
        }
        //si es más grande corta la cadena...
        if(a.length()>this.tamano_fecha_UTC){
            a = a.substring(0, this.tamano_fecha_UTC);
        }
        this.fecha_modificacion = a;
    }

    /***********************************************
     * Método: getCarpeta_archivo
     * Uso: obtiene lo que tiene carpeta_archivo
     * @return c - carpeta o a - archivo
    ***********************************************/
    public String getCarpeta_archivo() {
        return carpeta_archivo;
    }

    /***********************************************
     * Método: isArchivo
     * Uso: devuelve true si es un archivo
     * @return boolean con la respuesta
    ***********************************************/
    public boolean isArchivo() {
        try{
            char a = carpeta_archivo.charAt(0);

            if(a=='a'){
                //es un archivo
                return true;
            }
            return false;
        }catch(Exception exp){
            return false;
        }
    }

    /***********************************************
     * Método: isCarpeta
     * Uso: devuelve true si es una carpeta
     * @return boolean con la respuesta
    ***********************************************/
    public boolean isCarpeta() {
        try{
            char a = carpeta_archivo.charAt(0);
            if(a=='c'){
                //es un archivo
                return true;
            }
            return false;
        }catch(Exception exp){
            return false;
        }
    }

    /***********************************************
     * Método: setCarpeta_archivo
     * Uso: setea el tipo que es.. si archivo o carpeta
     * @parem carpeta_archivo
    ***********************************************/
    public boolean setCarpeta_archivo(String carpeta_archivo) {
        //para que sean 1
        String a = ""+carpeta_archivo;
        //si es más no se puede setear carpeta_archivo
        if(a.length()>this.tamano_carpeta){
            //a = a.substring(0, this.tamano_carpeta);
            return false;
        }
        try{
            if(a.charAt(0)!='c' && a.charAt(0)!='a'){
                return false;
            }
        }catch(Exception exp){
            return false;
        }
        this.carpeta_archivo = a;
        return true;
    }

    /***********************************************
     * Método: getId_padre
     * Uso: Devuelve el id_padre de este FCB
     * @return the id_padre
    ***********************************************/
    public String getId_padre() {
        return id_padre.trim();
    }

    /***********************************************
     * Método: getId_padre_value
     * Uso: Devuelve el id_padre de este FCB cono un valor numérico
     * @return the id_padre
    ***********************************************/
    public int getId_padre_value(){
        int a = 0;
        try{
            a = Integer.parseInt(this.id_padre.trim());
        }catch(Exception exp){
            return -1;
        }
        return a;
    }

    /***********************************************
     * Método: setId_padre
     * Uso: setea el contenido de id
     * @param id the id to set
    ***********************************************/
    public boolean setId_padre(String id_padre) {
        //para que sean 2
        String a = id_padre;
        //si es más grande no puede ser id
        if(a.length()>this.tamano_id){
            return false;
        }
        try{
            Integer.parseInt(a.trim());
        }catch(Exception exp){
            if(!a.trim().isEmpty()){
                return false;
            }
        }
        for(int i=a.length();i<this.tamano_id;i++){
            a+=" ";
        }
        this.id_padre = a;
        return true;
    }

    /***********************************************
     * Método: setId_padre
     * Uso: setea el contenido de id_padre
     * @param id_padre the id_padre to set
    ***********************************************/
    public void setId_padre(int id_padre) {
        int tam_a_completar = 0;
        if(id_padre>99 || id_padre<-1){
            tam_a_completar=this.tamano_id-0;
        }
        else if(id_padre>9 || id_padre==-1){
            tam_a_completar=this.tamano_id-2;
        }
        else{
            tam_a_completar=this.tamano_id-1;
        }
        String a = ""+id_padre;
        for(int i=0;i<tam_a_completar;i++){
            a+=" ";
        }
        this.id_padre = a;
    }

    /***********************************************
     * Método: getId_hermano
     * Uso: Devuelve el id_hermano de este FCB
     * @return the id_hermano
    ***********************************************/
    public String getId_hermano() {
        return id_hermano.trim();
    }

    /***********************************************
     * Método: getId_hermano_value
     * Uso: Devuelve el id_hermano de este FCB cono un valor numérico
     * @return the id_hermano
    ***********************************************/
    public int getId_hermano_value(){
        int a = 0;
        try{
            a = Integer.parseInt(this.id_hermano.trim());
        }catch(Exception exp){
            return -1;
        }
        return a;
    }

    /***********************************************
     * Método: setId_hermano
     * Uso: setea el contenido de id_hermano
     * @param id_hermano the id_hermano to set
    ***********************************************/
    public boolean setId_hermano(String id_hermano) {
        //para que sean 2
        String a = id_hermano;
        //si es más grande no puede ser id
        if(a.length()>this.tamano_id){
            return false;
        }
        try{
            Integer.parseInt(a.trim());
        }catch(Exception exp){
            if(!a.trim().isEmpty()){
                return false;
            }
        }
        for(int i=a.length();i<this.tamano_id;i++){
            a+=" ";
        }
        this.id_hermano = a;
        return true;
    }

    /***********************************************
     * Método: setId_hermano
     * Uso: setea el contenido de id_hermano
     * @param id_hermano the id_hermano to set
    ***********************************************/
    public void setId_hermano(int id_hermano) {
        int tam_a_completar = 0;
        if(id_hermano>99 || id_hermano<-1){
            tam_a_completar=this.tamano_id-0;
        }
        else if(id_hermano>9 || id_hermano==-1){
            tam_a_completar=this.tamano_id-2;
        }
        else{
            tam_a_completar=this.tamano_id-1;
        }
        String a = ""+id_hermano;
        for(int i=0;i<tam_a_completar;i++){
            a+=" ";
        }
        this.id_hermano = a;
    }
    
    /***********************************************
     * Método: setEspacioSinUtilizar
     * Uso: asigna el esepacio vacío de cada FCB
    ***********************************************/
    public void setEspacioSinUtilizar(){
        String cadena = " ";
        String vacio = "";
        for(int i=0;i<this.tamano_espacio_vacio;i++){
            vacio+=cadena;
        }
        this.Espacio_sin_utilizar = vacio;
    }
}